# -*- coding: utf-8 -*-

import mmap
import struct
import socket




class IP(object):
    def __init__(self, file_name):

        self.scenes_item = {
            "COM": "商业公司",
            "EDU": "教育机构",
            "GTW": "企业专线",
            "GOV": "政府机构",
            "IXP": "交换中心",
            "NET": "基础设施",
            "ORG": "组织机构",
            "SAT": "卫星通信",
            "DDT": "专用出口",
            "IDC/CDN": "数据中心/内容分发",
            "IDC/ANY": "数据中心/任播网络",
            "AUR": "已分配-未路由",
            "RNU": "已路由-未使用",
            "UND": "未分配",
            "WLA": "WLAN热点",
            "DYN": "家庭宽带",
            "IDC": "数据中心",
            "MOB": "移动网络",
        }

        self.datatype_item = {
            "1": "数据挖掘",
            "2": "地面采集",
        }

        self._handle = open(file_name, "rb")
        self.data = mmap.mmap(self._handle.fileno(), 0, access=mmap.ACCESS_READ)
        self.prefArr = []
        record_size = self.unpack_int_4byte(0)
        i = 0
        while i < 256:
            p = i * 8 + 4
            self.prefArr.append([self.unpack_int_4byte(p), self.unpack_int_4byte(p + 4)])
            i += 1
        self.endArr = []
        j = 0
        while j < record_size:
            p = 2052 + (j * 14)
            self.endArr.append(self.unpack_int_4byte(p))
            j += 1

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        self.close()

    def close(self):
        self._handle.close()

    def get_analysis(self, line_):
        line = line_.split("|")
        item = {}
        item['continent'] = line[0]   # 洲
        item['country'] = line[1]  # 国家/地区
        item['province'] = line[2]  # 省份
        item['city'] = line[3]  # 城市
        item['district'] = line[4]  # 区县
        item['isp'] = line[5]  # 运营商
        item['areaCode'] = line[6]  # 区域代码
        item['countryEnglish'] = line[7]  # 国家/地区英文
        item['countryEnglishShort'] = line[8]  #  国家/地区英文简写
        item['longitude'] = line[9]  # 经度
        item['latitude'] = line[10]  # 纬度
        item['elevation'] = line[11]  # 海拔
        item['zipCode'] = line[12]  # 邮编
        item['cityCode'] = line[13]  # 城市代码
        item['weatherStation'] = line[14]  # 气象站
        item['asn'] = line[15]  # asn
        item['scene'] = self.scenes_item.get(line[16])  # 场景
        item['street'] = line[17]  # 街道
        item['time'] = line[18]  # 时区
        item['company'] = line[19]  # 企业
        item['useUser'] = line[20]  # 使用人
        item['useType'] = line[21]  # 使用类型
        item['dataType'] = self.datatype_item.get(line[22])  # 定位方式


        return item

    def get(self, ip):
        ipdot = ip.split('.')
        prefix = int(ipdot[0])
        if prefix < 0 or prefix > 255 or len(ipdot) != 4:
            raise ValueError("invalid ip address")
        intIP = self.ip_to_int(ip)
        low = self.prefArr[prefix][0]
        high = self.prefArr[prefix][1]
        cur = low if low == high else self.search(low, high, intIP)
        return self.get_analysis(self.get_addr(cur))

    def search(self, low, high, k):
        M = 0
        while low <= high:
            mid = (low + high) // 2
            end_ip_num = self.endArr[mid]
            if end_ip_num >= k:
                M = mid
                if mid == 0:
                    break
                high = mid - 1
            else:
                low = mid + 1
        return M

    def ip_to_int(self, ip):
        _ip = socket.inet_aton(ip)
        return struct.unpack("!L", _ip)[0]

    def unpack_int_4byte(self, offset):
        return struct.unpack('<L', self.data[offset:offset + 4])[0]


    def unpack_int_8byte(self, offset):
        return struct.unpack('<Q', self.data[offset:offset + 8])[0]


    def unpack_int_2byte(self, offset):
        return struct.unpack('<H', self.data[offset:offset + 2])[0]

    def get_addr(self, j):
        p = 2052 + (j * 14)
        offset = self.unpack_int_8byte(4 + p)
        length = self.unpack_int_2byte(12 + p)
        return self.data[offset:offset + length].decode('utf-8')


if __name__ == '__main__':
    dat_files_name = r"ipdatacloud_split_street.dat"
    ip_ex = IP(dat_files_name)
    ip = "1.31.214.87"
    rest_ip = ip_ex.get(ip)
    print(rest_ip)